package very.util.rpc

import com.joyrec.util.log.impl.slf4j.ClassSlf4j
import org.json4s._
import org.json4s.JValue
import scalaj.http.Http
import very.util.http.Http4SRequestWrapper
import ws.very.util.json.JsonHelperWithDoubleMode
import org.json4s.native.Serialization.write
import very.util.response.Invalid

import scala.util.{ Failure, Success, Try }

case class RpcServerException(message: String) extends Exception with Invalid {
  override def errorMsg: String = message
}

trait RpcClient extends Http4SRequestWrapper with JsonHelperWithDoubleMode with ClassSlf4j {

  protected def host: String
  protected def secret: String
  protected def name: String

  val connTimeoutMS: Int = 2000
  val readTimeoutMs: Int = 10000

  def ask[A](url: String, request: A, headers: Seq[(String, String)] = Seq.empty)(
      implicit formats: Formats
  ): Either[Throwable, JValue] = {
    Try {
      Http(s"$host/$url")
        .header(Common.HEAD_KEY, secret)
        .postData(write(request))
        .headers(headers)
        .timeout(connTimeoutMS, readTimeoutMs)
        .asString
    } match {
      case Success(resp) =>
        val value = parseJson(resp.body)
        val JBool(isOk) = value \ "isOk"
        if (isOk) {
          Right(value \ "data")
        } else {
          val JString(message) = value \ "message"
          Left(RpcServerException(message))
        }
      case Failure(exception) =>
        Left(exception)
    }
  }
  def askG(url: String, headers: Seq[(String, String)] = Seq.empty): Either[Throwable, JValue] = {
    Try {
      Http(s"$host/$url")
        .header(Common.HEAD_KEY, secret)
        .headers(headers)
        .timeout(connTimeoutMS, readTimeoutMs)
        .asString
    } match {
      case Success(resp) =>
        val value = parseJson(resp.body)
        val JBool(isOk) = value \ "isOk"
        if (isOk) {
          Right(value \ "data")
        } else {
          val JString(message) = value \ "message"
          Left(RpcServerException(message))
        }
      case Failure(exception) =>
        Left(exception)
    }
  }

  def simpleAsk[A](url: String, request: A, headers: Seq[(String, String)] = Seq.empty)(
      implicit formats: Formats
  ): Either[RpcServerException, JValue] = {
    ask(url, request, headers) match {
      case Right(v)                    => Right(v)
      case Left(e: RpcServerException) => Left(e)
      case Left(e: Throwable) =>
        error(s"name:$name,$url error", e)
        Left(RpcServerException("服务连接异常，请稍后重试"))
    }
  }

  def simpleGAsk(url: String, headers: Seq[(String, String)] = Seq.empty): Either[RpcServerException, JValue] = {
    askG(url, headers) match {
      case Right(v)                    => Right(v)
      case Left(e: RpcServerException) => Left(e)
      case Left(e: Throwable) =>
        error(s"name:$name,$url error", e)
        Left(RpcServerException("服务连接异常，请稍后重试"))
    }
  }
}
